package com.rem.concurrency.multithreading.use;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.SneakyThrows;

/**
 * 测试生产者消费者模型-->利用缓冲区解决：管程法
 * 生产者 消费者 产品 缓冲区
 *
 * @author Rem
 * @date 2021/3/5
 */

public class TestPc {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();
        new Pro(container).start();
        new Conne(container).start();
    }
}

/**
 * 生产者
 */
@AllArgsConstructor
@Data
class Pro extends Thread {

    private SynContainer container;

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            this.getContainer().push(new Chicken(i));
            System.out.println("生产了" + i + "只");
        }
    }
}

/**
 * 消费者
 */
@AllArgsConstructor
@Data
class Conne extends Thread {

    private SynContainer container;

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了" + this.getContainer().pop().getId() + "只");
        }
    }
}

/**
 * 产品
 */
@AllArgsConstructor
@Data
class Chicken {

    private int id;

}

/**
 * 缓冲区/操作台
 */
class SynContainer {

    //需要一个容器大小
    private Chicken[] chinken = new Chicken[10];

    //容器计数器
    private int count = 0;

    /**
     * 生产者放入产品
     *
     * @param chicken
     */
    @SneakyThrows
    public synchronized void push(Chicken chicken) {
        //如果容器满了等待消费者消费
        if (count == chinken.length) {
            //需要通知消费者消费 生产等待
            this.wait();
        }

        //如果没有满就放入产品
        chinken[count] = chicken;
        count++;

        //通知消费者消费
        this.notify();

    }

    /**
     * 消费者消费产品
     *
     * @return
     */
    @SneakyThrows
    public synchronized Chicken pop() {
        //判断能否消费
        if (count == 0) {
            //等待生产者生产
            this.wait();
        }
        //如果可以消费
        count--;
        Chicken chicken = chinken[count];
        //通知生产者生产
        this.notify();
        return chicken;
    }
}